﻿using System;
using System.Collections.Generic;
using System.Threading;
using NsbExtensions.Messages.Management.Monitoring;
using NsbExtensions.Server.Management.EndpointMonitor;
using NsbExtensions.Tests.Stubs;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
using ObjectBuilder;
using ObjectBuilder.SpringFramework;

namespace NsbExtensions.Tests.ServerTests
{
    [TestFixture]
    public class EndpointManagementServerServiceTestFixture
    {
        private TestMessagingEndpoint CreateEndpoint(IBuilder builder)
        {
            var endpoint = (TestMessagingEndpoint) TestMessagingEndpoint.Create(builder);
            endpoint.AddMessageHandlerAssembly(typeof (EndpointMonitorServer).Assembly);
            return endpoint;
        }

        private EndpointMonitorServer CreateMonitorService(IBuilder builder, TestMessagingEndpoint endpoint)
        {
            builder.ConfigureComponent(typeof (EndpointMonitorServer), ComponentCallModelEnum.Singleton)
                .ConfigureProperty("EndpointMonitorInterval", TimeSpan.FromMinutes(10));

            var service = builder.Build<EndpointMonitorServer>();
            endpoint.AddLocalBackgroundService(service);
            return service;
        }

        [Test]
        public void ProcessIncomingMessages()
        {
            var builder = new Builder().Build<IBuilder>();


            TestMessagingEndpoint endpoint = CreateEndpoint(builder);
            EndpointMonitorServer svc = CreateMonitorService(builder, endpoint);
            var bus = (TestBus) endpoint.Bus;
            bus.PublishedMessages.Clear();
            bus.SentMessages.Clear();

            endpoint.Start();

            var onlineMessage = new EndpointOnlineNotification
                                    {
                                        EndpointID = "testid"
                                    };

            bus.ReceiveMessage(onlineMessage);

            List<EndpointMonitorServer.ActiveEndpoint> endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(1));

            Assert.That(endpoints[0].EndpointID, Is.EqualTo("testid"));
            Assert.AreSame(endpoints[0].LastStatus, onlineMessage);

            var statusMessage = new EndpointStatusUpdateNotification
                                    {
                                        EndpointID = "testid",
                                        StatusExpirationUtcTime = DateTime.Now.ToUniversalTime().AddMilliseconds(60)
                                    };

            svc.EndpointMonitorInterval = TimeSpan.FromMilliseconds(50);

            bus.ReceiveMessage(statusMessage);

            endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(1));

            Assert.That(endpoints[0].LastStatus, SyntaxHelper.Not.Null);
            Assert.AreSame(endpoints[0].LastStatus, statusMessage);

            Thread.Sleep(100);

            endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(0));

            Assert.That(bus.PublishedMessages.Count, Is.EqualTo(2));


            statusMessage.StatusExpirationUtcTime = DateTime.Now.ToUniversalTime().AddMinutes(1);
            bus.ReceiveMessage(statusMessage);

            endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(1));


            Thread.Sleep(100);

            endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(1));

            var offlineNotification = new EndpointOfflineNotification
                                          {
                                              EndpointID = "testid"
                                          };

            bus.ReceiveMessage(offlineNotification);

            endpoints = svc.GetAllActiveEndpoints();
            Assert.That(endpoints.Count, Is.EqualTo(0));

            Assert.That(bus.PublishedMessages.Count, Is.EqualTo(3));

            endpoint.Stop();
        }

        [Test]
        public void StartStopTest()
        {
            IBuilder builder = new Builder();

            TestMessagingEndpoint endpoint = CreateEndpoint(builder);
            EndpointMonitorServer svc = CreateMonitorService(builder, endpoint);


            endpoint.Start();
            Assert.IsTrue(svc.IsRunning);
            endpoint.Stop();
            Assert.IsFalse(svc.IsRunning);
        }
    }
}